package cn.hicard.risk.service.bd.impl;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.hicard.risk.common.Constant;
import cn.hicard.core.Page;
import cn.hicard.core.PageResult;
import cn.hicard.core.Where;
import cn.hicard.risk.dao.bd.TradefileinfoDao;
import cn.hicard.risk.entity.BdTradefileinfo;
import cn.hicard.risk.service.bd.TradefileinfoService;
import cn.hicard.util.DateHelp;
import cn.hicard.risk.vo.Poscreditratio;
import cn.hicard.risk.vo.PoscreditratioVo;
import cn.hicard.risk.vo.Postradedeviant;

/**
 * 传统POS商户的交易数据业务接口的实现类
 * @author zhangy
 *
 */
@Service
public class TradefileinfoServiceImpl implements TradefileinfoService {

	@Autowired
	private TradefileinfoDao tradefileinfoDao;

	//将传统POS商户的交易数据集合保存到数据库
	public String saveList(List<BdTradefileinfo> list) throws Exception {	
		
		// 设定本批导入的日期时间
		String datetime = DateHelp.dateNumber();
		
		StringBuffer sb = new StringBuffer();
		for (BdTradefileinfo trade : list) {			
			if(tradefileinfoDao.checkExistSysno(trade.getSysno(), trade.getTransdate())){
				// 已存在该系统参考号，记录
				sb.append(trade.getSysno());
				sb.append(",");
			}
			
			// 将主键设为空，为Hibernate保存准备
			trade.setPkTradefileinfo(null);
			// 设定导入日期时间
			trade.setImportdatetime(datetime);
			// 将文字的 交易类型转为字母，以防发生中文乱码及其它相关业整个查询失效
			// 2012年10月，清算业务变化，交易类型名称从中文变为数字：02=消费， 22=消费撤销
			trade.setTranstype(getTranstype(trade.getTranstypename()));
		}
		if(sb.length() > 0){
			sb.deleteCharAt(sb.length()-1);			
		}else{
			tradefileinfoDao.saveList(list);
		}
		return sb.toString();
	}
	
	/**
	 * 跟据 [中文]表述的 交易类型转为[数字] 编号<br/>
	 * 2012年10月清算业务变动，交易类型现在的数据是数字代码，代码依然写成兼容的形式
	 * @param transtype
	 * @return
	 */
	private String getTranstype(String transtype){
		
		// 对应[2012年10月清算业务变动]而添加的代码，同时向下兼容旧格式
		if("02".equals(transtype)){
			// 消费 1
			return Constant.TRADE_TYPE_CONSUME;
		}
		if("22".equals(transtype)){
			// 消费撤销 22 
			return Constant.TRADE_TYPE_CANCEL;
		}
		
		if(Constant.TRADE_TYPE_CONSUME_NAME.equals(transtype)){
			// 消费 1
			return Constant.TRADE_TYPE_CONSUME;
		}			
		else if(Constant.TRADE_TYPE_QUERY_NAME.equals(transtype)){
			// 余额查询 2
			return Constant.TRADE_TYPE_QUERY;
		}			
		else{
			// 未知 0
			return Constant.TRADE_TYPE_UNKNOW;
		}			
	}
	
	@Override
	public PageResult<BdTradefileinfo> search(Where where, Page page)
			throws Exception {
		return tradefileinfoDao.search(where, page);
	}
	
	/** 根据where据表述的条件查询实体集合，HQL与SQL同时支持，当心where中写错字段 */
	public List<BdTradefileinfo> findByWhere(Where where) throws Exception{
		return tradefileinfoDao.findByWhere(where);
	}

	//[start]传统POS风险交易报表
	
	/** 查询: 2.5.传统pos商户信用卡频繁交易报表 
	 * @throws Exception */	
	public List<BdTradefileinfo> findPoscreditoftentime(Where where, 
			double money, int count) throws Exception {
		// 查信用卡的交易
		List<BdTradefileinfo> list = tradefileinfoDao.findByWhere(where);
		// 返回结果用
		List<BdTradefileinfo> result = new ArrayList<BdTradefileinfo>();
		// 存放符合条件的数据的Map
		Map<String, Creditoftentime> resultMap = new HashMap<String, Creditoftentime>();
		// 方便存取临转换用，将List存入Map
		Map<Integer, BdTradefileinfo> tempMap = new HashMap<Integer, BdTradefileinfo>();
		// 按配置来筛选
		for (BdTradefileinfo trade : list) {	
			tempMap.put(trade.getPkTradefileinfo(), trade);	
			// 先达到交易额，再统计数量
			if(Double.parseDouble(trade.getTransmoney()) >= money){
				// 同一张卡号，同一个终端，同一天内，统计数量
				String key = trade.getCardno() + "," + trade.getTermno() + "," + trade.getTransdate();
				if(resultMap.containsKey(key)){
					Creditoftentime cft = resultMap.get(key);
					cft.count += 1;
					cft.pks.add(trade.getPkTradefileinfo());
				}else{
					Creditoftentime cft = new Creditoftentime(1, trade.getPkTradefileinfo());
					resultMap.put(key, cft);
				}
			}	
		}
		// 筛选出达到数量的
		Set<String> set = resultMap.keySet();
		for (String s : set) {
			Creditoftentime cft = resultMap.get(s);
			if(cft.count >= count){
				for (Integer pk : cft.pks) {
					result.add(tempMap.get(pk));
				}
			}
		}
		return result;		
	}
	/** 用来统计 传统pos商户信用卡频繁交易 数据结构的临时内部类 */
	private class Creditoftentime{
		public Creditoftentime(int c, Integer pk){
			count = c;
			pks = new ArrayList<Integer>();
			pks.add(pk);
		}
		public int count;
		public List<Integer> pks;
	}

	/** 查询: 2.2.传统pos商户信用卡比例报表 
	 * @throws Exception */
	public PoscreditratioVo findPoscreditratio(Where where) throws Exception {
		DecimalFormat df = new DecimalFormat("0.00");		
		PoscreditratioVo vo = new PoscreditratioVo();
		// 合计：交易笔数
		int totalCount = 0;
		// 合计：信用卡交易笔数
		int totalCreditCount = 0;
		// 合计：交易总额
		Double totalMoney = 0.0;
		// 合计：信用卡交易总额
		Double totalCreditMoney = 0.0;		
		// 最终要返回的"传统pos商户信用卡比例"
		List<Poscreditratio> creditratios = new ArrayList<Poscreditratio>();
		
		// A.先查商户[所有]的汇总数据
		List<Map<String, Object>> merchAllCollect = tradefileinfoDao.findCollect(where);
		// B.再查商户[信用卡的汇总]数据		
		// 添加信用卡类型条件
		where.addEqual("cardtype", '1');
		List<Map<String, Object>> merchCreditCollect = tradefileinfoDao.findCollect(where);
		
		/* 汇方式改变，使用终端号与商户号汇总，所以信用卡的交易与普通交易不一定一一对应
		 * 摆脱了数组方式 
		 */		 
		
		// 计算每一笔汇总数中信用卡交的比例
		for (int i = 0; i < merchAllCollect.size(); i++) {
			
			Map<String, Object> collect = merchAllCollect.get(i);
			// 合计的汇总数据
			totalCount += Integer.valueOf(collect.get("transcount").toString());
			totalMoney += Double.valueOf(collect.get("summoney").toString());
			
			/* 计算比例数据 */
			// 商户-终端 总的汇总数据
			String merchno = collect.get("merchno").toString();
			String termno = collect.get("termno").toString();
			
			Poscreditratio ratio = new Poscreditratio();			
			ratio.setMerchno(merchno);
			ratio.setMerchname(collect.get("merchname").toString());
			ratio.setTranscount(collect.get("transcount").toString());
			ratio.setTransmoney(df.format(Double.valueOf(collect.get("summoney").toString())));
			ratio.setArea(collect.get("area").toString());
			ratio.setTermno(termno);
			// 先默认没有信用卡交易数据
			ratio.setCredittranscount("0");
			ratio.setCredittransmoney("0.00");
			ratio.setMoneyratio("0.00" + Constant.SHOW_PERCENT_SIGN);
			ratio.setCountratio("0.00" + Constant.SHOW_PERCENT_SIGN);
			
			// 商户-终端 信用卡的汇总数据：按<商户号与终端号>查找对应的，如果找到相应的信用卡交易则将值更新
			for (int k = 0; k < merchCreditCollect.size(); k++) {
				Map<String, Object> collectCredit = merchCreditCollect.get(k);				
				if(merchno.equals(collectCredit.get("merchno").toString())
				   && termno.equals(collectCredit.get("termno").toString())){
					// 信用卡合计数据汇总
					totalCreditCount += Integer.parseInt(collectCredit.get("transcount").toString());
					totalCreditMoney += Double.parseDouble(collectCredit.get("summoney").toString());
					// 信用卡交易比例数据计算
					ratio.setCredittranscount(collectCredit.get("transcount").toString());
					ratio.setCredittransmoney(df.format(Double.valueOf(collectCredit.get("summoney").toString())));
					Double moneyRatio = Double.valueOf(ratio.getCredittransmoney()) / Double.valueOf(ratio.getTransmoney());
					Double countRatio = Double.valueOf(ratio.getCredittranscount()) / Double.valueOf(ratio.getTranscount());
					ratio.setMoneyratio(df.format(moneyRatio * 100.0) + Constant.SHOW_PERCENT_SIGN);
					ratio.setCountratio(df.format(countRatio * 100.0) + Constant.SHOW_PERCENT_SIGN);					
					break;
				}
			}
			// 单个信用卡比例数据组装完成，保存到集合中
			creditratios.add(ratio);
		}
		
		// 组装最终的VO对象
		vo.poscreditratios = creditratios;
		vo.totalMoney = df.format(totalMoney);
		vo.totalCreditMoney = df.format(totalCreditMoney);
		vo.totalCount = String.valueOf(totalCount);
		vo.totalCreditCount = String.valueOf(totalCreditCount);
		
		return vo;
	}

	/**
	 * 查询: 2.4.传统pos商户大额交易报表<br/>
	 * 同终端，同卡号，同一天内的累积大于等于20万
	 * @throws Exception 
	 */
	public List<BdTradefileinfo> findPosriskctrl(Where where) throws Exception {
		List<BdTradefileinfo> result = new ArrayList<BdTradefileinfo>();
		//  先查出一般条件的数据
		List<BdTradefileinfo> list = tradefileinfoDao.findByWhere(where);
		
		/*  按单个商户与单天日期进行累积  */
		
		// 存放符合条件的数据的Map
		Map<String, Bigmoneytrade> resultMap = new HashMap<String, Bigmoneytrade>();
		// 方便存取临转换用，将List存入Map
		Map<Integer, BdTradefileinfo> tempMap = new HashMap<Integer, BdTradefileinfo>();
		// 按配置来筛选
		for (BdTradefileinfo trade : list) {	
			tempMap.put(trade.getPkTradefileinfo(), trade);			
			// 同终端，同卡号，同一天的要求，统计单天总交易额
			String key = trade.getTermno()+ "," + trade.getCardno() + "," + trade.getTransdate();
			if(resultMap.containsKey(key)){
				Bigmoneytrade bmt = resultMap.get(key);
				bmt.money += Double.parseDouble(trade.getTransmoney());
				bmt.pks.add(trade.getPkTradefileinfo());
			}else{
				Bigmoneytrade bmt = new Bigmoneytrade(Double.parseDouble(trade.getTransmoney()), trade.getPkTradefileinfo());
				resultMap.put(key, bmt);
			}	
		}
		// 筛选出刚好[开始]“大于等于20万”的
		Set<String> set = resultMap.keySet();
		for (String s : set) {
			Bigmoneytrade bmt = resultMap.get(s);
			if(bmt.money >= 200000.00){
				for (Integer pk : bmt.pks) {
					result.add(tempMap.get(pk));
				}
			}
		}		
		return result;	
	}
	/** 用来统计 传统pos商户大额交易 数据结构的临时内部类 */
	private class Bigmoneytrade{
		public Bigmoneytrade(double m, Integer pk){
			money = m;
			pks = new ArrayList<Integer>();
			pks.add(pk);
		}
		public List<Integer> pks;
		public double money = 0.0;
	}

	/** 查询: 2.7.传统pos商户交易偏离值报表  
	 * @throws Exception */
	public List<Postradedeviant> findPostradedeviant(Where where1, Where where2, double change) throws Exception {
		/* 如果两个时间段内，商户在其中的一个时间上没有交易数据的话，
		 * 那么交易额比例变化为0或无穷大，
		 * 那么这个交易比例显示为<无>
		 */
		
		DecimalFormat df = new DecimalFormat("0.00");	
			
		List<Postradedeviant> list = new ArrayList<Postradedeviant>();
		
		Map<String, Postradedeviant> map = new HashMap<String, Postradedeviant>();
		
		// 商户在时间段1内的汇总数据 
		List<Map<String, Object>> merchAllCollect1 = tradefileinfoDao.findCollect(where1);
		
		// 商户在时间段2内的汇总数据
		List<Map<String, Object>> merchAllCollect2 = tradefileinfoDao.findCollect(where2);
		
		// 时间段1内的交易
		for (int i = 0; i < merchAllCollect1.size(); i++) {			
			Map<String, Object> collect1 = merchAllCollect1.get(i);
			String key = collect1.get("merchno").toString() + "," + collect1.get("termno").toString();
			
			Postradedeviant deviant = new Postradedeviant();
						
			deviant.setMerchno(collect1.get("merchno").toString());
			deviant.setMerchname(collect1.get("merchname").toString());
			// 地区
			deviant.setArea(collect1.get("area").toString());
			// 终端号
			deviant.setTermno(collect1.get("termno").toString());
			// 时间段1内的交易额
			deviant.setTransmoney1(df.format(Double.parseDouble(collect1.get("summoney").toString())));
			// 计算偏差值，默认时间段2内没有交易，百分比显示为"无"
			deviant.setTransmoney2("0.00");			
			deviant.setChangeratio(Constant.SHOW_UP_NONE);			 
			map.put(key, deviant);
		}
		
		// 时间段2内的交易
		for (int k = 0; k <  merchAllCollect2.size(); k++) {
			Map<String, Object> collect2 = merchAllCollect2.get(k);
			String key = collect2.get("merchno").toString() + "," + collect2.get("termno").toString();
			if(map.containsKey(key)){
				// 计算偏差值
				Postradedeviant deviant = map.get(key);
				deviant.setTransmoney2(df.format(Double.parseDouble(collect2.get("summoney").toString())));				
				double ratio = (Double.parseDouble(deviant.getTransmoney1()) - Double.parseDouble(deviant.getTransmoney2())) / Double.parseDouble(deviant.getTransmoney2());
				deviant.setChangeratio(df.format(ratio * 100.00));
			}else{
				// 在时间段1中没有交易信息，百分比显示为"无"
				Postradedeviant deviant = new Postradedeviant();				
				deviant.setMerchno(collect2.get("merchno").toString());
				deviant.setMerchname(collect2.get("merchname").toString());
				// 地区
				deviant.setArea(collect2.get("area").toString());
				// 终端号
				deviant.setTermno(collect2.get("termno").toString());
				// 时间段1内的交易额
				deviant.setTransmoney1("0.00");
				// 计算偏差值，默认时间段2内没有交易，按照要求设为<无>
				deviant.setTransmoney2(df.format(Double.parseDouble(collect2.get("summoney").toString())));			
				deviant.setChangeratio(Constant.SHOW_DOWN_NONE);			 
				map.put(deviant.getMerchno(), deviant);
			}
		}
		
		// 筛选最终需要的结果
		Set<String> set = map.keySet();
		for (String s : set) {
			Postradedeviant deviant = map.get(s);
			if(change > 0){
				if(Constant.SHOW_DOWN_NONE.equals(deviant.getChangeratio())){
					continue;
				}	
				if(Constant.SHOW_UP_NONE.equals(deviant.getChangeratio())){
					list.add(deviant);
					continue;
				}						
				if(Double.parseDouble(deviant.getChangeratio()) >= change){
					deviant.setChangeratio(deviant.getChangeratio() + Constant.SHOW_PERCENT_SIGN);					
					list.add(deviant);
				}
			}else{
				if(Constant.SHOW_UP_NONE.equals(deviant.getChangeratio())){
					continue;
				}
				if(Constant.SHOW_DOWN_NONE.equals(deviant.getChangeratio())){
					list.add(deviant);
					continue;
				}
				if(Double.parseDouble(deviant.getChangeratio()) <= change){
					deviant.setChangeratio(deviant.getChangeratio() + Constant.SHOW_PERCENT_SIGN);
					list.add(deviant);
				}
			}
		}
		return list;
	}

	//[end]传统POS风险交易报表
	

	//[start]从传统POS交易数据中筛选需要紧急调单的数据
	public List<BdTradefileinfo> findCallorder(String date) throws Exception{
		return tradefileinfoDao.findCallorder(date);
	}
	//[end]从传统POS交易数据中筛选需要紧急调单的数据
	
	public List<String> findLastDate() throws Exception{
		return tradefileinfoDao.findLastDate();
	}

}
